﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommonLib {
    public delegate double Operator(double a);

    public class DoubleTester {
        public static double Epsilon = 10e-10;
        public static void Assert(double a, double b) {
            double tmp = a - b;
            System.Diagnostics.Debug.Assert(IsZero(tmp));
        }
        public static bool IsZero(double d) {
            return -Epsilon <= d && d <= Epsilon;
        }
    }

    public struct Vector3 {
        public double x, y, z;

        public Vector3(double _x, double _y, double _z) {
            x = _x;
            y = _y;
            z = _z;
        }

        /// <summary>
        /// addition
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator +(Vector3 u, Vector3 v) {
            return new Vector3(u.x + v.x, u.y + v.y, u.z + v.z);
        }
        /// <summary>
        /// addition
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator +(Vector3 u, double v) {
            return new Vector3(u.x + v, u.y + v, u.z + v);
        }
        /// <summary>
        /// negative
        /// </summary>
        /// <param name="u"></param>
        /// <returns></returns>
        public static Vector3 operator -(Vector3 u) {
            return new Vector3(-u.x, -u.y, -u.z);
        }
        /// <summary>
        /// subtraction
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator -(Vector3 u, Vector3 v) {
            return new Vector3(u.x - v.x, u.y - v.y, u.z - v.z);
        }
        /// <summary>
        /// subtraction
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator -(Vector3 u, double v) {
            return new Vector3(u.x - v, u.y - v, u.z - v);
        }
        /// <summary>
        /// multiplication
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator *(double u, Vector3 v) {
            return new Vector3(u * v.x, u * v.y, u * v.z);
        }
        /// <summary>
        /// multiplication
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator *(Vector3 u, Vector3 v) {
            return new Vector3(u.x * v.x, u.y * v.y, u.z * v.z);
        }
        public static Vector3 operator *(Vector3 u, double v) {
            return new Vector3(u.x * v, u.y * v, u.z * v);
        }
        /// <summary>
        /// division
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator /(Vector3 u, double v) {
            return new Vector3(u.x / v, u.y / v, u.z / v);
        }
        /// <summary>
        /// division
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator /(Vector3 u, Vector3 v) {
            return new Vector3(u.x / v.x, u.y / v.y, u.z / v.z);
        }
        /// <summary>
        /// dot product
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static double operator &(Vector3 u, Vector3 v) {
            return u.x * v.x + u.y * v.y + u.z * v.z;
        }
        // cross product
        //         | i   j   k   |
        // u x v = | u.x u.y u.z |
        //         | v.x v.y v.z |
        /// <summary>
        /// cross prodoct
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Vector3 operator |(Vector3 u, Vector3 v) {
            return new Vector3(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x);
        }
        /// <summary>
        /// norm
        /// </summary>
        /// <param name="u"></param>
        /// <returns></returns>
        public static double operator ~(Vector3 u) {
            return Math.Sqrt(u.x * u.x + u.y * u.y + u.z * u.z);
        }
        /// <summary>
        /// normalize
        /// </summary>
        /// <param name="u"></param>
        /// <returns></returns>
        public static Vector3 operator !(Vector3 u) {
            double dist = ~u;
            return u / dist;
        }
        /// <summary>
        /// equals nearly
        /// </summary>
        /// <param name="u"></param>
        /// <returns></returns>
        public bool Equals(Vector3 u) {
            double e = DoubleTester.Epsilon;
            Vector3 d = this - u;
            return ((-e <= d.x && d.x <= e) && (-e <= d.y && d.y <= e) && (-e <= d.z && d.z <= e)) == true;
        }
        public Vector3 calc(Operator op) {
            return new Vector3(op(this.x), op(this.y), op(this.z));
        }
    }
}
